"""
网络通信模拟模块
在本地模拟客户端-服务器通信，用于演示网络编程技术
使用socket和多线程实现本地网络通信
"""
import socket
import threading
import json
from datetime import datetime
import logging
import time
import sys

class NetworkSimulator:
    """
    模拟网络通信，用于演示网络编程技术
    在本地创建客户端和服务器进行通信
    """
    
    def __init__(self, port=8888):
        self.port = port
        self.is_running = False
        self.server_socket = None
        self.server_thread = None
        self.clients = []
        self.logger = logging.getLogger(__name__)
        self.message_history = []
        self.client_count = 0
    
    def start_server(self):
        """启动本地服务器"""
        if self.is_running:
            self.logger.warning("服务器已经在运行")
            return False
        
        def server_thread():
            try:
                self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                self.server_socket.bind(('localhost', self.port))
                self.server_socket.listen(5)
                self.server_socket.settimeout(1.0)  # 设置超时以便定期检查停止标志
                self.is_running = True
                
                self.logger.info(f"网络模拟服务器已启动，端口: {self.port}")
                self._add_message("系统", f"服务器启动成功，监听端口 {self.port}")
                
                while self.is_running:
                    try:
                        client_socket, client_address = self.server_socket.accept()
                        self.client_count += 1
                        client_id = self.client_count
                        
                        self.logger.info(f"客户端连接: {client_address} (ID: {client_id})")
                        self._add_message("系统", f"客户端 {client_id} 连接: {client_address}")
                        
                        # 为每个客户端创建新线程
                        client_thread = threading.Thread(
                            target=self._handle_client,
                            args=(client_socket, client_address, client_id),
                            daemon=True
                        )
                        client_thread.start()
                        self.clients.append((client_socket, client_address, client_id, client_thread))
                        
                    except socket.timeout:
                        # 超时是正常的，用于检查停止标志
                        continue
                    except OSError as e:
                        if self.is_running:
                            self.logger.error(f"接受连接时出错: {e}")
                        break
                        
            except Exception as e:
                self.logger.error(f"服务器运行出错: {e}")
                self._add_message("系统", f"服务器错误: {e}")
            finally:
                self._cleanup_server()
        
        self.server_thread = threading.Thread(target=server_thread, daemon=True)
        self.server_thread.start()
        return True
    
    def _handle_client(self, client_socket, client_address, client_id):
        """处理客户端连接"""
        try:
            # 发送欢迎消息
            welcome = {
                "type": "welcome",
                "message": "连接到日程管理服务器成功",
                "client_id": client_id,
                "server_time": datetime.now().isoformat(),
                "supported_commands": ["time", "echo", "stats", "help"]
            }
            self._send_json(client_socket, welcome)
            
            while self.is_running:
                try:
                    data = client_socket.recv(1024).decode('utf-8')
                    if not data:
                        break  # 客户端断开连接
                    
                    self.logger.info(f"收到来自客户端 {client_id} 的消息: {data}")
                    self._add_message(f"客户端{client_id}", data)
                    
                    # 处理客户端请求
                    response = self._process_request(data, client_address, client_id)
                    self._send_json(client_socket, response)
                    
                except (ConnectionResetError, ConnectionAbortedError):
                    break
                except socket.timeout:
                    continue
                except Exception as e:
                    self.logger.error(f"处理客户端 {client_id} 数据时出错: {e}")
                    error_response = {
                        "type": "error",
                        "message": f"处理请求时出错: {str(e)}"
                    }
                    self._send_json(client_socket, error_response)
                    break
                    
        except Exception as e:
            self.logger.error(f"处理客户端 {client_id} 时出错: {e}")
        finally:
            client_socket.close()
            self._remove_client(client_id)
            self.logger.info(f"客户端断开连接: {client_address} (ID: {client_id})")
            self._add_message("系统", f"客户端 {client_id} 断开连接")
    
    def _process_request(self, request_data, client_address, client_id):
        """处理客户端请求"""
        try:
            request = json.loads(request_data)
            request_type = request.get('type', 'unknown')
            message = request.get('message', '')
            
            if request_type == 'time':
                response = {
                    "type": "time_response",
                    "server_time": datetime.now().isoformat(),
                    "client_id": client_id,
                    "client_address": str(client_address)
                }
                
            elif request_type == 'echo':
                response = {
                    "type": "echo_response",
                    "message": f"服务器回复: {message}",
                    "original_message": message,
                    "timestamp": datetime.now().isoformat(),
                    "client_id": client_id
                }
                
            elif request_type == 'stats':
                response = {
                    "type": "stats_response",
                    "client_count": len([c for c in self.clients if c[0].fileno() != -1]),
                    "message_count": len(self.message_history),
                    "server_uptime": self._get_uptime(),
                    "client_id": client_id,
                    "timestamp": datetime.now().isoformat()
                }
                
            elif request_type == 'help':
                response = {
                    "type": "help_response",
                    "commands": [
                        {"command": "time", "description": "获取服务器时间"},
                        {"command": "echo <message>", "description": "回声测试"},
                        {"command": "stats", "description": "获取服务器统计"},
                        {"command": "help", "description": "显示帮助信息"}
                    ],
                    "client_id": client_id
                }
                
            else:
                response = {
                    "type": "error",
                    "message": f"未知请求类型: {request_type}",
                    "supported_types": ["time", "echo", "stats", "help"],
                    "client_id": client_id
                }
                
        except json.JSONDecodeError:
            response = {
                "type": "error",
                "message": "无效的JSON格式",
                "client_id": client_id
            }
        
        return response
    
    def _send_json(self, client_socket, data):
        """发送JSON数据到客户端"""
        try:
            json_data = json.dumps(data, ensure_ascii=False, default=str)
            client_socket.send(json_data.encode('utf-8'))
        except Exception as e:
            self.logger.error(f"发送数据到客户端失败: {e}")
    
    def _remove_client(self, client_id):
        """从客户端列表中移除客户端"""
        self.clients = [c for c in self.clients if c[2] != client_id]
    
    def _cleanup_server(self):
        """清理服务器资源"""
        self.is_running = False
        
        # 关闭所有客户端连接
        for client_socket, _, client_id, _ in self.clients:
            try:
                client_socket.close()
            except:
                pass
        
        self.clients.clear()
        
        # 关闭服务器socket
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass
            self.server_socket = None
        
        self.logger.info("网络模拟服务器已停止")
        self._add_message("系统", "服务器已停止")
    
    def _get_uptime(self):
        """获取服务器运行时间（模拟）"""
        if hasattr(self, '_start_time'):
            uptime = datetime.now() - self._start_time
            return str(uptime).split('.')[0]  # 去掉微秒部分
        return "未知"
    
    def _add_message(self, sender, message):
        """添加消息到历史记录"""
        self.message_history.append({
            "sender": sender,
            "message": message,
            "timestamp": datetime.now()
        })
        
        # 保持最近100条消息
        if len(self.message_history) > 100:
            self.message_history.pop(0)
    
    def send_request(self, request_type, message=None):
        """模拟发送网络请求到服务器"""
        try:
            client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client_socket.settimeout(5)  # 5秒超时
            
            client_socket.connect(('localhost', self.port))
            
            request = {
                "type": request_type,
                "message": message,
                "timestamp": datetime.now().isoformat(),
                "client_name": "GUI客户端"
            }
            
            self._send_json(client_socket, request)
            
            # 接收响应
            response_data = client_socket.recv(1024).decode('utf-8')
            client_socket.close()
            
            response = json.loads(response_data)
            self._add_message("GUI客户端", f"发送请求: {request_type} - {message or ''}")
            return response
            
        except socket.timeout:
            error_msg = "连接超时，服务器可能未启动"
            self.logger.error(error_msg)
            return {
                "type": "error",
                "message": error_msg
            }
        except ConnectionRefusedError:
            error_msg = "连接被拒绝，服务器可能未启动"
            self.logger.error(error_msg)
            return {
                "type": "error",
                "message": error_msg
            }
        except Exception as e:
            error_msg = f"发送网络请求失败: {str(e)}"
            self.logger.error(error_msg)
            return {
                "type": "error",
                "message": error_msg
            }
    
    def get_message_history(self):
        """获取消息历史"""
        return self.message_history.copy()
    
    def get_server_status(self):
        """获取服务器状态"""
        return {
            "is_running": self.is_running,
            "port": self.port,
            "client_count": len(self.clients),
            "message_count": len(self.message_history),
            "uptime": self._get_uptime()
        }
    
    def stop_server(self):
        """停止服务器"""
        if not self.is_running:
            return
        
        self.logger.info("正在停止网络模拟服务器...")
        self.is_running = False
        
        # 如果服务器线程在运行，等待它结束
        if self.server_thread and self.server_thread.is_alive():
            self.server_thread.join(timeout=5)
        
        self._cleanup_server()
    
    def test_self_connection(self):
        """测试自身连接（用于演示）"""
        if not self.is_running:
            return {"type": "error", "message": "服务器未运行"}
        
        responses = []
        
        # 测试时间请求
        time_response = self.send_request("time")
        responses.append(("时间请求", time_response))
        
        # 测试回声请求
        echo_response = self.send_request("echo", "Hello, Server!")
        responses.append(("回声请求", echo_response))
        
        # 测试统计请求
        stats_response = self.send_request("stats")
        responses.append(("统计请求", stats_response))
        
        return responses

# 测试函数
def test_network_simulator():
    """测试网络模拟器"""
    print("测试网络模拟器...")
    
    # 创建网络模拟器
    net_sim = NetworkSimulator(port=8889)  # 使用不同端口避免冲突
    
    try:
        # 启动服务器
        if net_sim.start_server():
            print("服务器启动成功")
            
            # 等待服务器启动
            time.sleep(1)
            
            # 测试连接
            print("测试服务器连接...")
            responses = net_sim.test_self_connection()
            
            for test_name, response in responses:
                if response.get("type") != "error":
                    print(f"✓ {test_name}: 成功")
                else:
                    print(f"✗ {test_name}: 失败 - {response.get('message')}")
            
            # 显示服务器状态
            status = net_sim.get_server_status()
            print(f"服务器状态: {status}")
            
            # 显示消息历史
            messages = net_sim.get_message_history()
            print(f"消息历史 ({len(messages)} 条):")
            for msg in messages[-5:]:  # 显示最后5条
                print(f"  [{msg['timestamp'].strftime('%H:%M:%S')}] {msg['sender']}: {msg['message']}")
        
        else:
            print("服务器启动失败")
            
    except Exception as e:
        print(f"测试过程中出错: {e}")
    finally:
        # 停止服务器
        net_sim.stop_server()
        print("测试完成")

if __name__ == "__main__":
    # 配置日志
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # 测试网络模拟器
    test_network_simulator()